#include "stdafx.h"
#include "Scanner.h"


CScanner::CScanner()
    :m_currIndex(-1)
{}

CScanner::~CScanner(){}

void CScanner::SetSourseCode(std::vector<char> const & sourceCode)
{
    m_bufferCode = sourceCode;
    m_currIndex = 0;
}

std::string CScanner::GetValue() const
{
    return m_value;
}

CToken::TokenNames CScanner::GetNextToken()
{
    while (true)
    {
        m_ch = GetChar();
        switch (m_ch)
        {
        case EOF:
            return CToken::Eof;
        case ' ':
            continue;
        case '\n':
            continue;
        case '\r':
            continue;
        case '\t':
            continue;
        case '{':
            return CToken::LBrace;
        case '}':
            return CToken::RBrace;
        case '(':
            return CToken::LParen;
        case ')':
            return CToken::RParen;
        case '[':
            return CToken::LBraket;
        case ']':
            return CToken::RBraket;
        case '.':
            return CToken::Point;
        case ';':
            return CToken::Semicolon;
        case '!':
            return CToken::Not;
        case '<':
            return CToken::Less;
        case '+':
            return CToken::Add;
        case '-':
            return CToken::Sub;
        case '*':
            return CToken::Mult;
        case '=':
            return CToken::Assign;
        case '&':
            if (Peek() == '&')
            {
                m_currIndex++;
                return CToken::And;
            }
            else
            {
                return CToken::Incorrect;
            }
        default:
            if (m_ch >= '0' && m_ch <= '9')
            {
                return ReadNumber();
            }
            else if (isalpha(m_ch))
            {
                return ReadKeyWordOrIdentifier();
            }
            else
            {
                return CToken::Incorrect;
            }
        }
    }
}

char CScanner::Peek() const
{
    return (m_currIndex >= m_bufferCode.size()) ? EOF : m_bufferCode[m_currIndex];
}

char CScanner::GetChar()
{
    return (m_currIndex >= m_bufferCode.size()) ? EOF : m_bufferCode[m_currIndex++];
}

CToken::TokenNames CScanner::ReadNumber()
{
    m_value = "";
    
    while (m_ch != EOF && isdigit(m_ch))
    {
        m_value += m_ch;
        m_ch = GetChar();
    }
    
    if (m_ch != EOF)
        m_currIndex--;

    return CToken::Number;
}

CToken::TokenNames CScanner::ReadKeyWordOrIdentifier()
{
    m_value = "";
    while (m_ch != EOF && (isalpha(m_ch) || isdigit(m_ch)))
    {
        m_value += m_ch;
        m_ch = GetChar();
    }
    CToken::TokenNames token;
    
    return (IsKeyWord(m_value, token)) ? token : CToken::Id;
}

bool CScanner::IsKeyWord(std::string & const word, CToken::TokenNames & tokenName)
{
    if (!std::strcmp(word.c_str(), "class"))
    {
        tokenName = CToken::Class;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "extends"))
    {
        tokenName = CToken::Extends;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "public"))
    {
        tokenName = CToken::Public;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "static"))
    {
        tokenName = CToken::Static;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "void"))
    {
        tokenName = CToken::Void;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "main"))
    {
        tokenName = CToken::Main;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "true"))
    {
        tokenName = CToken::True;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "false"))
    {
        tokenName = CToken::False;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "int"))
    {
        tokenName = CToken::Int;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "boolean"))
    {
        tokenName = CToken::Boolean;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "String"))
    {
        tokenName = CToken::String;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "if"))
    {
        tokenName = CToken::If;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "while"))
    {
        tokenName = CToken::While;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "System.out.println"))
    {
        tokenName = CToken::PrintLn;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "return"))
    {
        tokenName = CToken::Return;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "length"))
    {
        tokenName = CToken::Length;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "new"))
    {
        tokenName = CToken::New;
        return true;
    }
    else if (!std::strcmp(word.c_str(), "this"))
    {
        tokenName = CToken::This;
        return true;
    }
    else 
    {
        return false;
    }
}

void CScanner::InitKeyWords()
{
    m_keyWords["class"] = CToken::Class;
    m_keyWords["extends"] = CToken::Extends;
    m_keyWords["public"] = CToken::Public;
    m_keyWords["static"] = CToken::Static;
    m_keyWords["void"] = CToken::Void;
    m_keyWords["main"] = CToken::Main;

    m_keyWords["true"] = CToken::True;
    m_keyWords["false"] = CToken::False;

    m_keyWords["int"] = CToken::Int;
    m_keyWords["boolean"] = CToken::Boolean;
    m_keyWords["String"] = CToken::String;

    m_keyWords["if"] = CToken::If;
    m_keyWords["while"] = CToken::While;
    m_keyWords["System.out.println"] = CToken::PrintLn;
    m_keyWords["return"] = CToken::Return;

    m_keyWords["length"] = CToken::Length;
    m_keyWords["new"] = CToken::New;

    m_keyWords["this"] = CToken::This;
}